module Pan
  
  class Backtracker
    attr_reader :objects, :snapshots
    def initialize
      @objects = []
      @snapshots = []
      @current_key = nil
    end
    
    def is_backtracked?(obj)
      @objects.include?(obj)
    end
    
    def register_object_for_backtracking(obj)
      @objects << obj
    end
    
    def snapshot(obj, key)
      raise Exception.new("object not registred") unless @objects.index(obj)
      @snapshots << [obj,obj.snapshot,key]
    end
    
    def restore(obj,key)
      o, snapshot, k = @snapshots.find{|o,s,k| obj==o and key == k}
      raise Exception.new("restore: nothing found under #{obj} #{key}") unless o
      obj.restore_from_snapshot(snapshot)
    end
    
    def snapshot_all(key)
      @objects.each do |obj|
        snapshot(obj,key)
      end
    end
    
    def restore_all(key)
      return if @current_key == key
      return if snapshots.size == 0
      @objects.each do |obj|
        restore(obj,key)
      end
      @current_key = key
    end
    
  end
  
  
  
  
  if __FILE__ == $0
    require 'core_ext'
    require 'pp'
    
    bt = Backtracker.new
    
    class Person 
      attr_accessor :name, :age, :address
      def initialize(name, age)
        @name, @age = name, age
        @address = Address.new
      end
    end
    
    class Address
      attr_accessor :street
    end
    
    p = Person.new("Bosse", 42)
    p.address.street = "Dalagatan"
    
    Struct.new("Name",:name)
    a = Address.new
    a.street = "Broadway"
    
    bt.register_object_for_backtracking(p)
    bt.register_object_for_backtracking(a)
    
    bt.snapshot_all("0000")
    
    puts "initial value"
    puts p.inspect
    puts a.inspect
    
    p.name = "Nisse"
    addr = Address.new
    addr.street = "Linegatan"
    p.address = addr
    
    a.street = "Brogatan"
    
    puts "changed values"
    
    puts p.inspect
    puts a.inspect
    
    bt.restore_all("0000")
    
    puts "restored values"
    
    puts p.inspect
    puts a.inspect
    
  end
  
end
